﻿namespace Stickam_Client
{
    public __gc class StickamHttp
    {
        // Nested Types
        public: __delegate void __gc* HostIDRetrievedEventHandler(Boolean __gc* IsSuccess, String __gc* HostID);


        public: __delegate void __gc* LoggedInEventHandler(String __gc* LoginData __gc [], Boolean __gc* IsSuccess);


        public: __delegate void __gc* RoomIPRetrievedEventHandler(Boolean __gc* IsSuccess, String __gc* RoomIP);


        public: __delegate void __gc* RoomlistRetrievedEventHandler(String __gc* RoomlistData, Boolean __gc* IsSuccess);


        // Events
        public: __event HostIDRetrievedEventHandler __gc* HostIDRetrieved;
        public: __event LoggedInEventHandler __gc* LoggedIn;
        public: __event RoomIPRetrievedEventHandler __gc* RoomIPRetrieved;
        public: __event RoomlistRetrievedEventHandler __gc* RoomlistRetrieved;

        // Methods
        public: StickamHttp()
        {
            this->HttpSocket = __gc new SocketConnector();
            this->Busy = false;
            this->LastLoginData = __gc new String __gc*[8];
            this->PlayerDomain = S"player.stickam.com";
            this->StickamDomain = S"www.stickam.com";
        }

        private: void __gc* DoConnect(String __gc* DomainName)
        {
            this->LastData = S"";
            String __gc* iP = String::Concat(Dns::GetHostAddresses(DomainName)[0]->ToString(), S":80");
            if (MySettingsProperty::Settings->HttpEnabled)
            {
                iP = MySettingsProperty::Settings->HttpIP;
            }
            this->HttpSocket->Connect(iP, MySettingsProperty::Settings->SocksIP, MySettingsProperty::Settings->SocksVersion, MySettingsProperty::Settings->SocksHTTP);
        }

        public: void __gc* GetHostID(String __gc* StickamURL)
        {
            this->Busy = true;
            this->LastURL = StickamURL;
            this->Mode = 5;
            this->DoConnect(this->StickamDomain);
        }

        public: void __gc* GetRoomIP(String __gc* RoomGet, String __gc* RoomType)
        {
            if (!this->Busy)
            {
                this->Busy = true;
                this->LastRoomGet = RoomGet;
                if (Conversions::ToDouble(RoomType) == 1)
                {
                    this->Mode = 3;
                }
                else
                {
                    this->Mode = 4;
                }
                this->DoConnect(this->PlayerDomain);
            }
            else
            {
                RoomIPRetrievedEventHandler __gc* roomIPRetrievedEvent = this->RoomIPRetrievedEvent;
                if (roomIPRetrievedEvent != 0)
                {
                    roomIPRetrievedEvent->Invoke(false, S"");
                }
            }
        }

        public: void __gc* GetRoomlist()
        {
            if (!this->Busy)
            {
                this->Busy = true;
                this->Mode = 2;
                this->DoConnect(this->StickamDomain);
            }
            else
            {
                RoomlistRetrievedEventHandler __gc* roomlistRetrievedEvent = this->RoomlistRetrievedEvent;
                if (roomlistRetrievedEvent != 0)
                {
                    roomlistRetrievedEvent->Invoke(S"[{}]", false);
                }
            }
        }

        private: void __gc* HttpSocket_Closed()
        {
            RoomIPRetrievedEventHandler __gc* roomIPRetrievedEvent;
            switch (this->Mode)
            {
                case 1:
                {
                    LoggedInEventHandler __gc* loggedInEvent;
                    this->Busy = false;
                    if (Strings::InStr(this->LastData, S"responseCode=0", CompareMethod::Binary) == 0)
                    {
                        this->LastLoginData = __gc new String __gc*[8];
                        loggedInEvent = this->LoggedInEvent;
                        if (loggedInEvent != 0)
                        {
                            loggedInEvent->Invoke(this->LastLoginData, false);
                        }
                        break;
                    }
                    this->LastLoginData[2] = S"";
                    this->LastLoginData[3] = Globals::GetParam(S"jsessionid", this->LastData, S"&");
                    this->LastLoginData[4] = this->LastLoginData[3];
                    this->LastLoginData[5] = S"";
                    this->LastLoginData[6] = S"";
                    this->LastLoginData[7] = Globals::GetParam(S"userId", this->LastData, S"&");
                    loggedInEvent = this->LoggedInEvent;
                    if (loggedInEvent != 0)
                    {
                        loggedInEvent->Invoke(this->LastLoginData, true);
                    }
                    break;
                }
                case 2:
                {
                    RoomlistRetrievedEventHandler __gc* roomlistRetrievedEvent;
                    this->Busy = false;
                    if (Strings::InStr(this->LastData, S"200 OK", CompareMethod::Binary) != 10)
                    {
                        roomlistRetrievedEvent = this->RoomlistRetrievedEvent;
                        if (roomlistRetrievedEvent != 0)
                        {
                            roomlistRetrievedEvent->Invoke(S"[{}]", false);
                        }
                        break;
                    }
                    this->LastData = Strings::Mid(this->LastData, (Strings::InStr(this->LastData, S"roomList = ", CompareMethod::Binary) + 11));
                    roomlistRetrievedEvent = this->RoomlistRetrievedEvent;
                    if (roomlistRetrievedEvent != 0)
                    {
                        roomlistRetrievedEvent->Invoke(Strings::Mid(this->LastData, 1, (Strings::InStr(this->LastData, S"}];\r\n", CompareMethod::Binary) + 3)), true);
                    }
                    break;
                }
                case 3:
                {
                    this->Busy = false;
                    if (Strings::InStr(this->LastData, S"serverIP=", CompareMethod::Binary) == 0)
                    {
                        roomIPRetrievedEvent = this->RoomIPRetrievedEvent;
                        if (roomIPRetrievedEvent != 0)
                        {
                            roomIPRetrievedEvent->Invoke(false, S"");
                        }
                        break;
                    }
                    roomIPRetrievedEvent = this->RoomIPRetrievedEvent;
                    if (roomIPRetrievedEvent != 0)
                    {
                        roomIPRetrievedEvent->Invoke(true, Globals::GetParam(S"serverIP", this->LastData, S"&"));
                    }
                    break;
                }
                case 4:
                {
                    this->Busy = false;
                    if (Strings::InStr(this->LastData, S"errorCode=0", CompareMethod::Binary) == 0)
                    {
                        roomIPRetrievedEvent = this->RoomIPRetrievedEvent;
                        if (roomIPRetrievedEvent != 0)
                        {
                            roomIPRetrievedEvent->Invoke(false, S"");
                        }
                        break;
                    }
                    roomIPRetrievedEvent = this->RoomIPRetrievedEvent;
                    if (roomIPRetrievedEvent != 0)
                    {
                        roomIPRetrievedEvent->Invoke(true, String::Concat(Globals::GetParam(S"serverIP", this->LastData, S"&"), S"-", Globals::GetParam(S"channelID", this->LastData, S"&")));
                    }
                    break;
                }
                case 5:
                {
                    HostIDRetrievedEventHandler __gc* hostIDRetrievedEvent;
                    this->Busy = false;
                    if (Strings::InStr(this->LastData, S"The user was not found.", CompareMethod::Binary) != 0)
                    {
                        hostIDRetrievedEvent = this->HostIDRetrievedEvent;
                        if (hostIDRetrievedEvent != 0)
                        {
                            hostIDRetrievedEvent->Invoke(false, S"");
                        }
                        break;
                    }
                    this->LastData = Strings::Mid(this->LastData, (Strings::InStr(this->LastData, S"new ProfileUpdater(", CompareMethod::Binary) + 0x13));
                    hostIDRetrievedEvent = this->HostIDRetrievedEvent;
                    if (hostIDRetrievedEvent != 0)
                    {
                        hostIDRetrievedEvent->Invoke(true, Strings::Mid(this->LastData, 1, (Strings::InStr(this->LastData, S")", CompareMethod::Binary) - 1)));
                    }
                    break;
                }
            }
        }

        private: void __gc* HttpSocket_Connected()
        {
            switch (this->Mode)
            {
                case 1:
                {
                    this->HttpSocket->SendData(Globals::HttpGet(this->StickamDomain, String::Concat(__gc new String __gc*[5] {
                        S"/servlet/flash/authenticateUser?j_username=", this->LastLoginData[0], S"&j_password=", this->LastLoginData[1], S"&type=99998"}), S""));
                    break;
                }
                case 2:
                {
                    this->HttpSocket->SendData(Globals::HttpGet(this->StickamDomain, S"/chatRoom.do", S""));
                    break;
                }
                case 3:
                {
                    this->HttpSocket->SendData(Globals::HttpGet(this->PlayerDomain, String::Concat(S"/servlet/flash/getRoomServer?roomID=", this->LastRoomGet, S"&type=chatroom"), S""));
                    break;
                }
                case 4:
                {
                    this->HttpSocket->SendData(Globals::HttpGet(this->PlayerDomain, String::Concat(S"/servlet/flash/getChannel?performerID=", this->LastRoomGet, S"&isEvent=false&type=join&hostid=", this->LastRoomGet), S""));
                    break;
                }
                case 5:
                {
                    this->HttpSocket->SendData(Globals::HttpGet(this->StickamDomain, String::Concat(S"/", this->LastURL), S""));
                    break;
                }
            }
        }

        private: void __gc* HttpSocket_ConnectFail()
        {
            this->Busy = false;
            switch (this->Mode)
            {
                case 1:
                {
                    this->LastLoginData = __gc new String __gc*[8];
                    LoggedInEventHandler __gc* loggedInEvent = this->LoggedInEvent;
                    if (loggedInEvent != 0)
                    {
                        loggedInEvent->Invoke(this->LastLoginData, false);
                    }
                    break;
                }
                case 2:
                {
                    RoomlistRetrievedEventHandler __gc* roomlistRetrievedEvent = this->RoomlistRetrievedEvent;
                    if (roomlistRetrievedEvent != 0)
                    {
                        roomlistRetrievedEvent->Invoke(S"[{}]", false);
                    }
                    break;
                }
                case 3:
                {
                    RoomIPRetrievedEventHandler __gc* roomIPRetrievedEvent = this->RoomIPRetrievedEvent;
                    if (roomIPRetrievedEvent != 0)
                    {
                        roomIPRetrievedEvent->Invoke(false, S"");
                    }
                    break;
                }
            }
        }

        private: void __gc* HttpSocket_DataArrival(String __gc* Data)
        {
            this->LastData = String::Concat(this->LastData, Data);
        }

        public: void __gc* Login(String __gc* Email, String __gc* Pass)
        {
            if (!this->Busy)
            {
                this->Busy = true;
                this->LastLoginData[0] = Email;
                this->LastLoginData[1] = Pass;
                this->LoginStep = 1;
                this->Mode = 1;
                this->DoConnect(this->StickamDomain);
            }
            else
            {
                this->LastLoginData = __gc new String __gc*[8];
                LoggedInEventHandler __gc* loggedInEvent = this->LoggedInEvent;
                if (loggedInEvent != 0)
                {
                    loggedInEvent->Invoke(this->LastLoginData, false);
                }
            }
        }


        // Properties
        [DebuggerNonUserCode]
        private: __property virtual SocketConnector __gc* get_HttpSocket()
        {
            return this->_HttpSocket;
        }
        [MethodImpl(MethodImplOptions::Synchronized), DebuggerNonUserCode]
        private: __property virtual void __gc* set_HttpSocket(SocketConnector __gc* WithEventsValue)
        {
            DataArrivalEventHandler __gc* handler = new DataArrivalEventHandler __gc*(this.HttpSocket_DataArrival);
            ConnectedEventHandler __gc* handler2 = new ConnectedEventHandler __gc*(this.HttpSocket_Connected);
            ConnectFailEventHandler __gc* handler3 = new ConnectFailEventHandler __gc*(this.HttpSocket_ConnectFail);
            ClosedEventHandler __gc* handler4 = new ClosedEventHandler __gc*(this.HttpSocket_Closed);
            if (this->_HttpSocket != 0)
            {
                this->_HttpSocket->DataArrival -= handler;
                this->_HttpSocket->Connected -= handler2;
                this->_HttpSocket->ConnectFail -= handler3;
                this->_HttpSocket->Closed -= handler4;
            }
            this->_HttpSocket = WithEventsValue;
            if (this->_HttpSocket != 0)
            {
                this->_HttpSocket->DataArrival += handler;
                this->_HttpSocket->Connected += handler2;
                this->_HttpSocket->ConnectFail += handler3;
                this->_HttpSocket->Closed += handler4;
            }
        }


        // Fields
        [AccessedThroughProperty(S"HttpSocket")]
        private: SocketConnector __gc* _HttpSocket;
        private: Boolean __gc* Busy;
        private: HostIDRetrievedEventHandler __gc* HostIDRetrievedEvent;
        private: String __gc* LastData;
        private: String __gc* LastLoginData __gc [];
        private: String __gc* LastRoomGet;
        private: String __gc* LastURL;
        private: LoggedInEventHandler __gc* LoggedInEvent;
        private: Int32 __gc* LoginStep;
        private: Int32 __gc* Mode;
        private: String __gc* PlayerDomain;
        private: RoomIPRetrievedEventHandler __gc* RoomIPRetrievedEvent;
        private: RoomlistRetrievedEventHandler __gc* RoomlistRetrievedEvent;
        private: String __gc* StickamDomain;
    };
}

